package com.ruben.aop;

import com.alibaba.fastjson.JSON;
import com.ruben.pojo.User;
import com.ruben.utils.AjaxJson;
import com.ruben.utils.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.UndeclaredThrowableException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;

/**
 * @ClassName: SayWordAop
 * @Description: 说话Aop
 * @Date: 2020/8/7 19:36
 * *
 * @author: achao<achao1441470436 @ gmail.com>
 * @version: 1.0
 * @since: JDK 1.8
 */
@Slf4j
@Aspect
@Component
public class SayWordAop {

    /**
     * 指定say方法
     */
    @Pointcut("execution(* com.ruben.controller.UserController.say(..))")
    private void pointcut() {
    }

    /**
     * 返回前对参数进行处理，加上前缀
     *
     * @param point
     * @param returnValue
     */
    @AfterReturning(pointcut = "pointcut()", returning = "returnValue")
    public void addPrefix(JoinPoint point, Object returnValue) {
        if (returnValue instanceof HashMap) {
            Map<String, Object> result = (Map<String, Object>) returnValue;
            result.put("data", "achao对你说：" + result.get("data"));
        }
    }

    /**
     * 登录参数校验(已废弃，采用Hibernate Validator方式进行校验)
     *
     * @param point
     * @return
     * @throws Throwable
     */
    @Deprecated
//    @Around("execution(* com.ruben.controller.UserController.login(..))")
    public Object permissionCheck(ProceedingJoinPoint point) throws Throwable {
        List<Object> paramList = Arrays.asList(point.getArgs());
        AtomicBoolean passValidate = new AtomicBoolean(true);
        String pattern = "^[A-Za-z0-9]{4,40}$";
        AtomicReference<String> errorMsg = new AtomicReference<>("您输入的参数格式有误");
        paramList.forEach(param -> {
            User user = (User) param;
            if (!Pattern.matches(pattern, user.getUsername())) {
                errorMsg.set("用户名格式错误");
                passValidate.set(false);
            } else if (!Pattern.matches(pattern, user.getPassword())) {
                errorMsg.set("密码格式错误");
                passValidate.set(false);
            }
        });
        if (!passValidate.get()) {
            Map<String, Object> map = new HashMap<>(1 << 2);
            map.put("success", false);
            map.put("code", -629);
            map.put("msg", errorMsg.get());
            return map;
        }
        return point.proceed();
    }

    /**
     * 在com.ruben包下任意方法执行前打印日志
     *
     * @param point
     */
//    @Before(value = "execution(* com.ruben.*.*.*(..))")
    public void logRecode(JoinPoint point) {
        log.info("==>参数：" + Arrays.toString(point.getArgs()));
    }

    /**
     * 在com.ruben.controller包下任意方法执行后打印
     *
     * @param point
     */
    @After("execution(* com.ruben.controller.*.*(..))")
    public void recodeWord(JoinPoint point) {
        log.info("<==" + point.getSignature().getDeclaringTypeName() + "." + point.getSignature().getName() + "方法执行结束");
    }

    /**
     * 记录日志计时
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("execution(* com.ruben.controller.*.*(..))")
    public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
        long beginTime = System.currentTimeMillis();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Object result = null;
        if (Optional.ofNullable(joinPoint).isPresent()) {
            result = joinPoint.proceed();
        }
        long endTime = System.currentTimeMillis();
        log.info("计时结束：" + new SimpleDateFormat("hh:mm:ss.SSS").format(endTime) + "  耗时：" + TimeUtil.formatDateTime(endTime - beginTime) + "  URI: " + request.getRequestURI() + "  最大内存: " + Runtime.getRuntime().maxMemory() / 1024 / 1024 + "m  已分配内存: " + Runtime.getRuntime().totalMemory() / 1024 / 1024 + "m  已分配内存中的剩余空间: " + Runtime.getRuntime().freeMemory() / 1024 / 1024 + "m  最大可用内存: " + (Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory() + Runtime.getRuntime().freeMemory()) / 1024 / 1024 + "m");
        return result;
    }

    /**
     * 打印返回参数
     *
     * @param point
     * @param returnValue
     */
//    @AfterReturning(pointcut = "execution(* com.ruben.*.*.*(..))", returning = "returnValue")
    @AfterReturning(pointcut = "execution(* com.ruben.controller.*.*(..))", returning = "returnValue")
    public void recodeLogReturnValue(JoinPoint point, Object returnValue) {
        log.info("<==返回值：" + JSON.toJSONString(returnValue));
    }

}
